package com.coldlz.mmp.proxy.handlerserver;

import com.coldlz.mmp.proxy.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;
import java.util.List;


public class ServerProxyHttpHandler extends ChannelDuplexHandler {

    private final Logger log = LoggerFactory.getLogger(ServerProxyHttpHandler.class);
    private final UserContext userContext;

    volatile RemoteClient remoteClient;

    public ServerProxyHttpHandler(UserContext userContext) {
        this.userContext = userContext;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object object) throws Exception {
        if (object instanceof FullHttpRequest fullHttpRequest) {
            proxyFullHttpRequest(ctx, fullHttpRequest);
        } else if (object instanceof HttpObject httpObject) {
            proxyHttpObject(httpObject);
        } else if (object instanceof WebSocketFrame wsFrame) {
            proxyWebSocketFrame(wsFrame);
        } else {
            throw new RuntimeException("类型转换异常 " + object.getClass());
        }
    }

    private void proxyWebSocketFrame(WebSocketFrame wsFrame) {
        ByteBuf copy = wsFrame.content().copy();
        System.out.println("代理的数据： " + copy.readCharSequence(copy.readableBytes(), Charset.defaultCharset()));


        RemoteClient remoteClient = getRemoteClient();
        remoteClient.writeAndFlush(wsFrame, future -> {
            if (!future.isSuccess()) {
                log.error("发送 WebSocketFrame 异常...", future.cause());
            }
        });
    }

    private synchronized RemoteClient getRemoteClient() {
        if (remoteClient == null) {
            remoteClient = RemoteClientFactory.getClient(userContext);
        }
        return remoteClient;
    }

    private void proxyHttpObject(HttpObject httpObject) {
        // 判断是否存在拦截器
        List<Object> interceptors = userContext.getInterceptors();
        if (httpObject instanceof HttpMessage httpMessage) {
            //log.info("proxy HttpMessage...uri={}", ((HttpRequest) httpMessage).uri());
            proxyHttpMessage(httpMessage);
        } else if (httpObject instanceof HttpContent httpContent) {
            if (httpObject instanceof LastHttpContent lastHttpContent) {
                // 说明数据包已经发送完毕，这里将进行记录
                //log.info("proxy LastHttpContent...");
            } else {
                //log.info("proxy HttpContent...");
            }
            proxyHttpContent(httpContent);
        }
    }

    private void proxyHttpContent(HttpContent httpContent) {
        HttpContent newHttpContent = httpContent.copy();
        getRemoteClient().writeAndFlush(httpContent, future -> {
            if (!future.isSuccess()) {
                log.error("发送 HttpContent 异常...", future.cause());
            } else {
                // 记录发送的数据
                userContext.getRecordInterceptor().recordRequestHttpContent(newHttpContent, userContext.getProxyInfo());
            }
            if (newHttpContent.refCnt() > 0) {
                ReferenceCountUtil.release(newHttpContent);
            }
        });
    }

    private void proxyHttpMessage(HttpMessage httpMessage) {
        getRemoteClient().writeAndFlush(httpMessage, future -> {
            if (!future.isSuccess()) {
                log.error("发送 HttpMessage 异常...", future.cause());
            } else {
                // 记录发送的数据
                userContext.getRecordInterceptor().recordRequestHttpMessage(httpMessage, userContext.getProxyInfo());
            }
        });
    }

    private void proxyFullHttpRequest(ChannelHandlerContext ctx, FullHttpRequest r) {
        log.info("proxy FullHttpRequest uri={}", r.uri());
        ProxyInfo info = userContext.getProxyInfo();
        FullHttpRequest newRequest = r;
        for (Object item : userContext.getInterceptors()) {
            if (item instanceof Interceptor interceptor) {
                newRequest = interceptor.modifyRequest(newRequest, info);
            }
        }
        if (newRequest == r) {
            newRequest = r.copy();
        }
        RemoteClient remoteClient = getRemoteClient();
        FullHttpRequest newRequestFinal = newRequest;
        remoteClient.writeAndFlush(newRequest, (ChannelFuture future) -> {
            if (!future.isSuccess()) {
                log.error("send message failed", future.cause());
            }
//            if (ReferenceCountUtil.refCnt(newRequestFinal.content()) > 0) {
//                ReferenceCountUtil.safeRelease(newRequestFinal.content());
//            }
//            if (!future.isSuccess()) {
//                userContext.close();
//            }
        });
    }


    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        super.write(ctx, msg, promise);
    }
}
